`include "top.vh"
`include "csr.vh"

module csr(
    input           clk,
    input           reset,
    input           csr_we,
    input   [13:0]  csr_num,
    input   [31:0]  csr_wmask,
    input   [31:0]  csr_wvalue,
    output  [31:0]  csr_rvalue,
    output  [31:0]  ex_entry,
    output  [31:0]  era_entry,
    output          has_int,
    input           ertn_flush,
    input           ws_ex,
    input   [ 5:0]  ws_ecode,
    input   [ 8:0]  ws_esubcode,
    input   [31:0]  ws_pc,
    input   [31:0]  ws_vaddr
);

reg [ 1:0]  csr_crmd_plv;
reg         csr_crmd_ie;
reg         csr_crmd_da;
reg         csr_crmd_pg;

reg [ 1:0]  csr_prmd_pplv;
reg         csr_prmd_pie;

reg [12:0]  csr_estat_is;
reg [21:16] csr_estat_ecode;
reg [30:22] csr_estat_esubcode;

reg [31:0]  csr_era_pc;

reg  [31:0] csr_badv_vaddr;

reg [25:0]  csr_eentry_va;

reg [12:0]  csr_ecfg_lie;

reg  [8:0]  csr_cpuid_coreid;

reg [31:0]  csr_save0_data;
reg [31:0]  csr_save1_data;
reg [31:0]  csr_save2_data;
reg [31:0]  csr_save3_data;

reg  [31:0] csr_tid_tid;
reg         csr_tcfg_en;
reg         csr_tcfg_periodic;
reg  [29:0] csr_tcfg_initval;
wire [31:0] tcfg_next_value;
reg [31:0]  timer_cnt;

wire ex_addr_err;

wire    csr_ticlr_clr;
assign  csr_ticlr_clr = 1'b0;

wire    [31:0]  csr_crmd_rvalue     =   {27'b0,csr_crmd_pg,csr_crmd_da,csr_crmd_ie,csr_crmd_plv};
wire    [31:0]  csr_prmd_rvalue     =   {29'b0, csr_prmd_pie, csr_prmd_pplv};
wire    [31:0]  csr_ecfg_rvalue     =   {19'b0, csr_ecfg_lie};
wire    [31:0]  csr_estat_rvalue    =   {1'b0,csr_estat_esubcode,csr_estat_ecode,3'b0,csr_estat_is};
wire    [31:0]  csr_era_rvalue      =   {csr_era_pc};
wire    [31:0]  csr_badv_rvalue     =   {csr_badv_vaddr};
wire    [31:0]  csr_eentry_rvalue   =   {csr_eentry_va,6'b0};
wire    [31:0]  csr_save0_rvalue    =   {csr_save0_data};
wire    [31:0]  csr_save1_rvalue    =   {csr_save1_data};
wire    [31:0]  csr_save2_rvalue    =   {csr_save2_data};
wire    [31:0]  csr_save3_rvalue    =   {csr_save3_data};
wire    [31:0]  csr_tid_rvalue      =   {csr_tid_tid};
wire    [31:0]  csr_tcfg_rvalue     =   {csr_tcfg_initval, csr_tcfg_periodic, csr_tcfg_en};
wire    [31:0]  csr_tval_rvalue     =   {timer_cnt};

assign  ex_entry    =   csr_eentry_rvalue;
assign  era_entry   =   csr_era_rvalue;
assign  has_int     =   ((csr_estat_is[11:0] & csr_ecfg_lie[11:0]) != 12'b0)
                    &&  (csr_crmd_ie == 1'b1);

always @(posedge clk ) begin
    if (reset)
        csr_crmd_da  <= 1'b1;
end

always @(posedge clk ) begin
    if (reset)  
        csr_crmd_pg  <= 1'b0;
end

always @(posedge clk) begin
    if (reset)
        csr_crmd_plv <= 2'b0;
    else if (ws_ex)
        csr_crmd_plv <= 2'b0;
    else if (ertn_flush)
        csr_crmd_plv <= csr_prmd_pplv;
    else if (csr_we && csr_num==`CSR_CRMD)
        csr_crmd_plv <= csr_wmask[`CSR_CRMD_PLV]&csr_wvalue[`CSR_CRMD_PLV]
                     | ~csr_wmask[`CSR_CRMD_PLV]&csr_crmd_plv;
end


always @(posedge clk) begin
    if (reset)
        csr_crmd_ie <= 1'b0;
    else if (ws_ex)
        csr_crmd_ie <= 1'b0;
    else if (ertn_flush)
        csr_crmd_ie <= csr_prmd_pie;
    else if (csr_we && csr_num==`CSR_CRMD)
        csr_crmd_ie <= csr_wmask[`CSR_CRMD_IE]&csr_wvalue[`CSR_CRMD_IE]
                    | ~csr_wmask[`CSR_CRMD_IE]&csr_crmd_ie;
end


always @(posedge clk) begin
    if (ws_ex) begin
        csr_prmd_pplv <= csr_crmd_plv;
        csr_prmd_pie <= csr_crmd_ie;
    end
    else if (csr_we && csr_num==`CSR_PRMD) begin
        csr_prmd_pplv <= csr_wmask[`CSR_PRMD_PPLV]&csr_wvalue[`CSR_PRMD_PPLV]
                      | ~csr_wmask[`CSR_PRMD_PPLV]&csr_prmd_pplv;
        csr_prmd_pie <= csr_wmask[`CSR_PRMD_PIE]&csr_wvalue[`CSR_PRMD_PIE]
                     | ~csr_wmask[`CSR_PRMD_PIE]&csr_prmd_pie;
    end
end


always @(posedge clk) begin
    if (reset)
        csr_ecfg_lie <= 13'b0;
    else if (csr_we && csr_num==`CSR_ECFG)
        csr_ecfg_lie <= csr_wmask[`CSR_ECFG_LIE]&csr_wvalue[`CSR_ECFG_LIE]
                     | ~csr_wmask[`CSR_ECFG_LIE]&csr_ecfg_lie;
end



always @(posedge clk) begin
    if (reset)
        csr_estat_is[10:0] <= 11'b0;
    else if (csr_we && csr_num==`CSR_ESTAT) begin
        csr_estat_is[1:0] <= csr_wmask[`CSR_ESTAT_IS10]&csr_wvalue[`CSR_ESTAT_IS10]
                          | ~csr_wmask[`CSR_ESTAT_IS10]&csr_estat_is[1:0];
        csr_estat_is[9:2] <= 8'b0;//hw_int_in[7:0];//exp12未出现
        csr_estat_is[10] <= 1'b0;
    end
    if (timer_cnt[31:0]==32'b0)
        csr_estat_is[11] <= 1'b1;
    else if (csr_we && csr_num==`CSR_TICLR && csr_wmask[`CSR_TICLR_CLR]
            && csr_wvalue[`CSR_TICLR_CLR]) begin
        csr_estat_is[11] <= 1'b0;
        csr_estat_is[12] <= 1'b0;//ipi_int_in;//exp12未出现
    end
end

always @(posedge clk) begin
    if (ws_ex) begin
        csr_estat_ecode <= ws_ecode;
        csr_estat_esubcode <= ws_esubcode;
    end
end


always @(posedge clk) begin
    if (ws_ex)
        csr_era_pc <= ws_pc;
    else if (csr_we && csr_num==`CSR_ERA)
        csr_era_pc <= csr_wmask[`CSR_ERA_PC]&csr_wvalue[`CSR_ERA_PC]
                   | ~csr_wmask[`CSR_ERA_PC]&csr_era_pc;
end

assign ex_addr_err = (ws_ecode == `ECODE_ADE && ws_esubcode == `ESUBCODE_ADEF) || ws_ecode == `ECODE_ALE;
always @(posedge clk ) begin
    if (ws_ex && ex_addr_err)
        csr_badv_vaddr <= (ws_ecode == `ECODE_ADE && ws_esubcode == `ESUBCODE_ADEF) ? ws_pc : ws_vaddr;
end

always @(posedge clk ) begin
    if (reset)
        csr_cpuid_coreid <= 9'h0;
end

//SVAE
always @(posedge clk) begin
    if (csr_we && csr_num==`CSR_SAVE0)
        csr_save0_data <= csr_wmask[`CSR_SAVE_DATA]&csr_wvalue[`CSR_SAVE_DATA]
                       | ~csr_wmask[`CSR_SAVE_DATA]&csr_save0_data;
    if (csr_we && csr_num==`CSR_SAVE1)
        csr_save1_data <= csr_wmask[`CSR_SAVE_DATA]&csr_wvalue[`CSR_SAVE_DATA]
                       | ~csr_wmask[`CSR_SAVE_DATA]&csr_save1_data;
    if (csr_we && csr_num==`CSR_SAVE2)
        csr_save2_data <= csr_wmask[`CSR_SAVE_DATA]&csr_wvalue[`CSR_SAVE_DATA]
                       | ~csr_wmask[`CSR_SAVE_DATA]&csr_save2_data;
    if (csr_we && csr_num==`CSR_SAVE3)
        csr_save3_data <= csr_wmask[`CSR_SAVE_DATA]&csr_wvalue[`CSR_SAVE_DATA]
                       | ~csr_wmask[`CSR_SAVE_DATA]&csr_save3_data;
end

always @(posedge clk ) begin
    if (csr_we && csr_num==`CSR_EENTRY)
        csr_eentry_va <= csr_wmask[`CSR_EENTRY_VA]&csr_wvalue[`CSR_EENTRY_VA]
                       | ~csr_wmask[`CSR_EENTRY_VA]&csr_eentry_va;
end

//TIMER
always @(posedge clk ) begin
    if (reset)
        csr_tid_tid <= {23'h0, csr_cpuid_coreid};           //TODO:定义coreid_in
    else if (csr_we && csr_num == `CSR_TID) begin
        csr_tid_tid <= csr_wmask[`CSR_TID_TID]&csr_wvalue[`CSR_TID_TID]
                        | ~csr_wmask[`CSR_TID_TID]&csr_tid_tid;
    end
end

always @(posedge clk ) begin
    if (reset)
        csr_tcfg_en <= 1'b0;
    else if (csr_we && csr_num == `CSR_TCFG) begin
        csr_tcfg_en <= csr_wmask[`CSR_TCFG_EN]&csr_wvalue[`CSR_TCFG_EN]
                        | ~csr_wmask[`CSR_TCFG_EN]&csr_tcfg_en;
    end

    if (csr_we && csr_num == `CSR_TCFG) begin
        csr_tcfg_periodic <= csr_wmask[`CSR_TCFG_PERIOD]&csr_wvalue[`CSR_TCFG_PERIOD]
                        | ~csr_wmask[`CSR_TCFG_PERIOD]&csr_tcfg_periodic;
        csr_tcfg_initval <= csr_wmask[`CSR_TCFG_INITV]&csr_wvalue[`CSR_TCFG_INITV]
                        | ~csr_wmask[`CSR_TCFG_INITV]&csr_tcfg_initval;
    end
end

assign tcfg_next_value = csr_wmask[31:0]&csr_wvalue[31:0]
                        | ~csr_wmask[31:0]&csr_tcfg_rvalue; //{csr_tcfg_initval, csr_tcfg_periodic, csr_tcfg_en};

always @(posedge clk ) begin
    if (reset)
        timer_cnt <= 32'hffffffff;
    else if (csr_we && csr_num == `CSR_TCFG && tcfg_next_value[`CSR_TCFG_EN])
        timer_cnt <= {tcfg_next_value[`CSR_TCFG_INITV], 2'b0};
    else if (csr_tcfg_en && timer_cnt != 32'hffffffff) begin
        if (timer_cnt == 32'b0 && csr_tcfg_periodic)
            timer_cnt <= {csr_tcfg_initval, 2'b0};
        else
            timer_cnt <= timer_cnt - 1'b1;
    end
end

assign  csr_rvalue  =   {32{csr_num == `CSR_CRMD}}  & csr_crmd_rvalue
                    |   {32{csr_num == `CSR_PRMD}}  & csr_prmd_rvalue
                    |   {32{csr_num == `CSR_ECFG}}  & csr_ecfg_rvalue
                    |   {32{csr_num == `CSR_ESTAT}} & csr_estat_rvalue
                    |   {32{csr_num == `CSR_ERA}}   & csr_era_rvalue
                    |   {32{csr_num == `CSR_BADV}}  & csr_badv_rvalue
                    |   {32{csr_num == `CSR_EENTRY}}& csr_eentry_rvalue
                    |   {32{csr_num == `CSR_SAVE0}} & csr_save0_rvalue
                    |   {32{csr_num == `CSR_SAVE1}} & csr_save1_rvalue
                    |   {32{csr_num == `CSR_SAVE2}} & csr_save2_rvalue
                    |   {32{csr_num == `CSR_SAVE3}} & csr_save3_rvalue
                    |   {32{csr_num == `CSR_TID}}   & csr_tid_rvalue
                    |   {32{csr_num == `CSR_TICLR}} & {31'b0,csr_ticlr_clr}
                    ;


endmodule